package main.java.com.negromotad.controller;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import main.java.com.negromotad.configuration.TMGeneticAlgorithmConfigurator;
import main.java.com.negromotad.genetics.TMChromosome;
import main.java.com.negromotad.genetics.rules.TMAsociatedCostJepRule;
import main.java.com.negromotad.genetics.rules.TMJepRule;
import main.java.com.negromotad.genetics.rules.TMRule;
import main.java.com.negromotad.model.TMAlgorithmObserver;
import main.java.com.negromotad.model.TMRunManager;
import main.java.com.negromotad.parser.TMDataLoader;
import main.java.com.negromotad.view.MainView;

import org.jgap.Gene;

public class DefaultController implements TMAlgorithmObserver {

	private TMRunManager runManager;
	private MainView mainView;
	private List<TMRule> rules;

	public void addModel(TMRunManager model) {
		this.runManager = model;
	}

	public void addView(MainView mainView) {
		this.mainView = mainView;

	}

	public void loadData(String absolutePath) {
		runManager.loadData(absolutePath);
	}

	public TMDataLoader getLoader() {
		return runManager.getTmDataLoader();
	}

	public void setAlgorithmConfiguration(
			TMGeneticAlgorithmConfigurator tmAlgorithmConfigurator) {
		this.runManager.setAlgorithmConfigurator(tmAlgorithmConfigurator);
		if (this.mainView != null)
			this.mainView.resetProgressBar();
	}

	public void startRun(int target, int expectative) {
		this.runManager.startRun(expectative, target, this);
	}

	public void stopRun() {
		this.runManager.stopRun();
	}

	@Override
	public void update(TMChromosome chromosome, int evolution, boolean goOn, boolean maxFailure) {
		if (!goOn && maxFailure) {
			mainView.failure(chromosome);
		} else {
			double total = chromosome.getFitnessValue();
			Gene[] gene = chromosome.getGenes();
			String partialResult = "";
			for (int i = 0; i < gene.length; i++) {
				partialResult = partialResult + gene[i].getAllele().toString()
						+ " - ";
			}
			double risk = chromosome.getRisk(this.getLoader().getEntry(),
					runManager.getTmRun().getExpectative(), this.getLoader()
							.getRows(), this.getLoader().getCols());
			mainView.addPartialResultRow(total, evolution, partialResult, risk);
			if (!goOn || runManager.getAlgorithmConfigurator()
							.getMaxAllowedEvolution() == (evolution + 1)) {
				Integer[] aux = new Integer[gene.length];
				for (int i = 0; i < gene.length; i++) {
					aux[i] = (Integer) gene[i].getAllele();
				}
				mainView.addResultRow(aux);
				mainView.setFinalResults(risk,total);
				if(!goOn && !maxFailure){
					mainView.reached();
				}
			}
		}
	}

	private void setRules(List<TMRule> rules) {
		runManager.setRules(rules);
	}

	public boolean validRules(String text, String[] vars) {
		if ("".equals(text)) {
			return true;
		}
		String[] aux = text.split("\n");
		List<String> listVars = new ArrayList<String>();
		rules = new ArrayList<TMRule>();
		for (int i = 0; i < vars.length; i++) {
			listVars.add(vars[i]);
		}
		for (int i = 0; i < aux.length; i++) {
			if (!aux[i].equals("")) {
				TMJepRule rule = new TMJepRule(aux[i]);
				rules.add(rule);
			}
		}
		for (TMRule tmRule : rules) {
			if (!tmRule.checkExpression(listVars)) {
				return false;
			}
		}
		this.setRules(rules);
		return true;
	}

	public boolean validRulesCA(Object[][] data, String[] vars, String text) {
		if ("".equals(text)) {
			return true;
		}
		String[] arrayExpressions = text.split("\n");
		List<String> listVars = new ArrayList<String>();
		Map<String, Double> asociatedCostsMap = new HashMap<String, Double>();
		rules = new ArrayList<TMRule>();
		for (int i = 0; i < vars.length; i++) {
			listVars.add(vars[i]);
			asociatedCostsMap.put(vars[i], (Double) data[0][i + 1]);
		}
		final String REGEX = "CA_";
		Pattern pattern = Pattern.compile(REGEX);
		Matcher matcher = null;

		for (int i = 0; i < arrayExpressions.length; i++) {
			matcher = pattern.matcher(arrayExpressions[i]);
			if (matcher.find()) {
				TMAsociatedCostJepRule rule = new TMAsociatedCostJepRule(
						arrayExpressions[i], asociatedCostsMap);
				rules.add(rule);
			} else {
				TMJepRule rule = new TMJepRule(arrayExpressions[i]);
				rules.add(rule);
			}
			matcher.reset();
		}

		for (TMRule tmRule : rules) {
			if (!tmRule.checkExpression(listVars)) {
				return false;
			}
		}
		this.setRules(rules);
		return true;
	}
}
